#include "myapplication.h"
#include <mmsystem.h>
#include "glext.h"

myApplication * myApplication::s_pInstance = NULL;

// you can use constructor to initialise variables
myApplication::myApplication()
: theCamera(NULL)
, theProjectiles(NULL)
, theSoundEngine(NULL)
, Sound_Footstep(NULL)
{
}

myApplication::~myApplication()
{
	if (theRoot != NULL)
	{
		delete theRoot;
		theRoot = NULL;
	}
	if (theFrustum != NULL)
	{
		delete theFrustum;
		theFrustum = NULL;
	}
	if (theSoundEngine != NULL)
	{
		theSoundEngine->drop();
	}
	if (theProjectiles != NULL)
	{
		delete [] theProjectiles;
		theProjectiles = NULL;
	}	
	if (theCamera != NULL)
	{
		delete theCamera;
		theCamera = NULL;
	}
}

myApplication* myApplication::getInstance()
{
	if(s_pInstance == NULL)
	{
		s_pInstance = new myApplication();
	}

	return s_pInstance;
}

void myApplication::drop()
{
	if(s_pInstance != NULL)
	{
		delete s_pInstance;
		s_pInstance = NULL;
	}
}

void myApplication::Draw3DEnvironment()
{
	renderGround();
	renderSky();

}

void myApplication::Update(void) 
{
	// update interactions based on mouse inputs
	if (mouseInfo.mLButtonUp == GLUT_DOWN) {
		printf("press and hold\n");
		//	Add codes to manage the bullets shot out and the remaining bullets
		theProjectiles[ m_iProjectileIndex ].SetActivate( true );
		theProjectiles[ m_iProjectileIndex ].SetPosition( theCamera->GetPosition() );
		theProjectiles[ m_iProjectileIndex ].SetDirection( theCamera->GetDirection() );
		m_iProjectileIndex++;
		if (m_iProjectileIndex == MAXPROJECTILES)
			m_iProjectileIndex = 0;

		printf("position[%6.4f, %6.4f, %6.4f], direction[%6.4f, %6.4f, %6.4f]\n", theCamera->GetPosition().x, theCamera->GetPosition().y, theCamera->GetPosition().z,
		theCamera->GetDirection().x, theCamera->GetDirection().y, theCamera->GetDirection().z);
	}
	else {
		//printf("released\n");
	}

	// update movement based on keyboard inputs
	if(myKeys['w'] == true)
		moveMeForward(true, 1.0f);
	if(myKeys['a'] == true)
		moveMeSideway(true, 1.0f);
	if(myKeys['s'] == true)
		moveMeForward(false, 1.0f);
	if(myKeys['d'] == true)
		moveMeSideway(false, 1.0f);
	if(myKeys[VK_ESCAPE] == true)
		exit(0);
	if(myKeys['q'] == true)
		if (theRoot) theRoot->ApplyTranslate( 0.1f, 0.0f, 0.0f );
	if(myKeys['e'] == true)
		if (theRoot) theRoot->ApplyTranslate( -0.1f, 0.0f, 0.0f );

	if(theFrustum)
	{
		theFrustum->Update();
		if(theFrustum->ContainmentCheck( theRoot->GetTopLeft() ) && theFrustum->ContainmentCheck( theRoot->GetBottomRight() ))
		{
			//The scene graph is inside the frustum!
			theRoot->SetColor( 1.0f, 1.0f, 1.0f );
		}
		else if (theFrustum->ContainmentCheck( theRoot->GetTopLeft() ) == true && theFrustum->ContainmentCheck( theRoot->GetBottomRight() ) == false )
		{
			//The scene graph is PARTIALLY inside the frustum!
			theRoot->SetColor( 0, 1.0f, 0 );
		}
		else if (theFrustum->ContainmentCheck( theRoot->GetTopLeft() ) == false && theFrustum->ContainmentCheck( theRoot->GetBottomRight() ) == true )
		{
			//The scene graph is PARTIALLY inside the frustum!
			theRoot->SetColor( 0, 1.0f, 0 );
		}
		else if (theFrustum->ContainmentCheck( theRoot->GetTopLeft() ) == true
				 theFrustum->ContainmentCheck( theRoot->GetTopLeft() ) == false
		else
		{
			//The scene graph is outside the frustum!
			theRoot->SetColor( 1.0f, 0, 0 );
		}
	}
}

void myApplication::renderScene(void) {
	// Clear the buffer
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();

	glEnable(GL_DEPTH_TEST);

	theCamera->Update();

	// Set current colour to red
	glPushMatrix();
		glColor3f(1.0,0.0,0.0);

		// Draw a triangle
		glBegin(GL_TRIANGLES);
			glVertex3f(-0.5, 0.5, 0.0);
			glVertex3f(0.5, 2.0, 0.0);
			glVertex3f(0.0, 2.5, 0.0);
		glEnd();
	glPopMatrix();


	float deltaTime = (timeGetTime()-timelastcall);
	if (deltaTime>1000/frequency)
	{
		// Calculate the framerate
		calculateFPS();

		timelastcall=timeGetTime();

		Update();
	}

	Draw3DEnvironment();

	// Draw the scene graph
	theRoot->Draw();

	//Draw the frustum
	theFrustum->Draw();

	for (int i=0; i<MAXPROJECTILES; i++)
	{
		//if (theProjectiles[i].GetStatus())
		theProjectiles[i].Update();
	}

	// Enable 2D text display and HUD
	theCamera->SetHUD( true );

	// Display framerate
	drawFPS();
	// Display ammo and health
	glColor3f( 1.0f, 1.0f, 1.0f);
	printw (25.0, 100.0, 0, "Ammo: ___/100");
	printw (25.0, 130.0, 0, "Health: ___/100");

	// MiniMap
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_STENCIL_TEST);

	// draw circle to the stencil buffer.
	glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); // replace pixel in stencil buffer
	glStencilFunc(GL_ALWAYS, 1, 0xffffffff); //always draw, replace stencil buffer pixel with 1

		glBegin(GL_TRIANGLE_FAN);
			for (int i=0; i < 360; i++)
			{
				glVertex2f(65.0f+cos(i*3.142/180)*50.0f,505.0f+sin(i*3.142/180)*50.0f);
			}
		glEnd();

		// render minimap
		glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
		glStencilFunc(GL_EQUAL, 1, 0xffffffff);  // draw if stencil == 1 

		glPushMatrix();
			glEnable(GL_BLEND);
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			glBindTexture(GL_TEXTURE_2D, grassTexture[0].texID);
			glPushMatrix();
				glTranslatef(4.0,450.0,0.0);
				glBegin(GL_QUADS);
					int height = 100 * 1.333/1.5;
					glTexCoord2f(0,0); glVertex2f(10,10);
					glTexCoord2f(1,0); glVertex2f(10,10 + height);
					glTexCoord2f(1,1); glVertex2f(110,10 + height);
					glTexCoord2f(0,1); glVertex2f(110,10);	
				glEnd();
			glPopMatrix();
			glDisable(GL_BLEND);
		glPopMatrix();
		glDisable(GL_TEXTURE_2D);

	glDisable(GL_STENCIL_TEST);

	// Player icon in minimap
	glPushMatrix();
		glColor3f(1.0f,1.0f,0.0f);
		glTranslatef(65.0, 510.0,0.0);
		glPushMatrix();
			glRotatef( atan2(theCamera->GetDirection().x, theCamera->GetDirection().z) * 180/3.142, 0, 0, 1);
			glBegin(GL_TRIANGLES);
				glVertex2f( 0.0f, -10.0f );
				glVertex2f( 5.0f, 10.0f );
				glVertex2f( -5.0f, 10.0f );
			glEnd();
		glPopMatrix();
	glPopMatrix();

	DrawHealthBar(100, 150);

	theCamera->SetHUD( false );

	// Flush off any entity which is not drawn yet, so that we maintain the frame rate.
	glFlush();

	// swapping the buffers causes the rendering above to be shown
	glutSwapBuffers();
}

void myApplication::changeSize(int w, int h) {

	// Prevent a divide by zero, when window is too short
	// (you cant make a window of zero width).
	if(h == 0)
		h = 1;

	float ratio = (float) (1.0f* w / h);

	// Reset the coordinate system before modifying
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	
	// Set the viewport to be the entire window
	glViewport(0, 0, w, h);

	// Set the correct perspective.
	gluPerspective(45,ratio,1,1000);
	glMatrixMode(GL_MODELVIEW);
}

float myApplication::calculateDistanceMoved( float acceleration, float maxVelocity, float timeDiff )
{
	//d = (u + (10m/s2) * timeDiff) * timeDiff
	float currentVelocity = previousVelocity + acceleration * timeDiff;
	if (currentVelocity > maxVelocity)
		currentVelocity = maxVelocity;
	float distanceMoved = currentVelocity * timeDiff;
	previousVelocity = currentVelocity;
	return distanceMoved;
}

void myApplication::moveMeForward(bool mode, float timeDiff) 
{
	//if (Sound_Footstep == NULL)
	//	Sound_Footstep = theSoundEngine->play2D("footsteps.mp3", false, true);
	//if (Sound_Footstep->getIsPaused() == true)
	//	Sound_Footstep->setIsPaused( false );
	//else if (Sound_Footstep->isFinished() == true)
	//	theSoundEngine->play2D( Sound_Footstep->getSoundSource(), false, true);

	if (mode)
	{
//		printf( "previousVelocity=%6.4f\n", previousVelocity);
		theCamera->Walk( calculateDistanceMoved( 0.01f, 50.0f, timeDiff ) );
/*		theCameraPosition.x += theCameraDirection.x;//deltaMove.x;
		theCameraPosition.y += theCameraDirection.y;//deltaMove.y;
		theCameraPosition.z += theCameraDirection.z;//deltaMove.z;
		*/
	}
	else
	{
		theCamera->Walk( -1.0f );
/*		theCameraPosition.x -= theCameraDirection.x;//deltaMove.x;
		theCameraPosition.y -= theCameraDirection.y;//deltaMove.y;
		theCameraPosition.z -= theCameraDirection.z;//deltaMove.z;
		*/
	}
}

void myApplication::moveMeSideway(bool mode, float timeDiff)
{
	if (mode)
	{
		theCamera->Strafe( -1.0f );
	}
	else
	{
		theCamera->Strafe( 1.0f );
	}
}

void myApplication::orientMe(float ang) 
{
	theCamera->Yaw( ang );
}


void myApplication::inputKey(int key, int x, int y) {

	switch (key) {
		case GLUT_KEY_LEFT : 
			moveMeSideway(true, 1.0f);break;
		case GLUT_KEY_RIGHT : 
			moveMeSideway(false, 1.0f);break;
		case GLUT_KEY_UP : 
			moveMeForward(true, 1.0f);break;
		case GLUT_KEY_DOWN : 
			moveMeForward(false, 1.0f);break;
	}
}

void myApplication::KeyboardDown(unsigned char key, int x, int y){

	myKeys[key]= true;
}

void myApplication::KeyboardUp(unsigned char key, int x, int y){

	myKeys[key]= false;
}

void myApplication::MouseMove (int x, int y) {
	int diffX = x - mouseInfo.lastX;
	int diffY = y - mouseInfo.lastY;

	//Update on y axis
	theCamera->Pitch( diffY * 3.142f / 180.0f );

	////Update on x and z axis
	angle += (float) diffX * 3.142f / 180.0f;
	if (angle > 6.284f)
		angle -= 6.284f;
	else if (angle < -6.284f)
		angle += 6.284f;
	theCamera->Yaw( -angle );

	mouseInfo.lastX = x;
	mouseInfo.lastY = y;

	//Checking mouse boundary. //	 800 is the window width. You may need to change this to suit your program.
	if  (mouseInfo.lastX > 800-20 || mouseInfo.lastX < 20)
	{
		mouseInfo.lastX = (800 >> 1);
		glutWarpPointer(mouseInfo.lastX, mouseInfo.lastY);
	}
	//	 600 is the window height. You may need to change this to suit your program.
	if (mouseInfo.lastY > 600-20 || mouseInfo.lastY < 20)
	{
		mouseInfo.lastY = (600 >> 1);
		glutWarpPointer(mouseInfo.lastX, mouseInfo.lastY);
	}
}

void myApplication::MouseClick(int button, int state, int x, int y) {
	switch (button) {

		case GLUT_LEFT_BUTTON:
			mouseInfo.mLButtonUp = state;
			mouseInfo.lastX = x;
			mouseInfo.lastY = y;

			break;

		case GLUT_RIGHT_BUTTON:
			break;

		case GLUT_MIDDLE_BUTTON:
			break;
	}
}

bool myApplication::Init(void)
{
	// Set camera position
	theCamera = new Camera( Camera::LAND_CAM );
	theCamera->SetPosition( 0.0, 2.0, -5.0 );
	theCamera->SetDirection( 0.0, 0.0, 1.0 );

	glEnable(GL_TEXTURE_2D);							// Enable Texture Mapping ( NEW )
	if (!LoadTGA(&grassTexture[0],"grass.tga"))				// Load The grass Texture
		return false;										// If Loading Failed, Return False
	if (!LoadTGA(&grassTexture[1],"grass_darkgreen.tga"))	// Load The grass Texture
		return false;										// If Loading Failed, Return False
	if (!LoadTGA(&grassTexture[2],"grass_lightgreen.tga"))	// Load The grass Texture
		return false;										// If Loading Failed, Return False
	if (!LoadTGA(&grassTexture[3],"grass_darkgreen.tga"))	// Load The grass Texture
		return false;										// If Loading Failed, Return False
	if (!LoadTGA(&grassTexture[4],"grass_lightgreen.tga"))	// Load The grass Texture
		return false;										// If Loading Failed, Return False

	if (!LoadTGA(&skyTexture[0],"SkyBox/red_north.tga"))				// Load The Font Texture
		return false;										// If Loading Failed, Return False
	if (!LoadTGA(&skyTexture[1],"SkyBox/red_south.tga"))				// Load The Font Texture
		return false;										// If Loading Failed, Return False
	if (!LoadTGA(&skyTexture[2],"SkyBox/red_west.tga"))				// Load The Font Texture
		return false;										// If Loading Failed, Return False
	if (!LoadTGA(&skyTexture[3],"SkyBox/red_east.tga"))				// Load The Font Texture
		return false;										// If Loading Failed, Return False
	if (!LoadTGA(&skyTexture[4],"SkyBox/red_up.tga"))				// Load The Font Texture
		return false;										// If Loading Failed, Return False
	if (!LoadTGA(&skyTexture[5],"SkyBox/red_down.tga"))				// Load The Font Texture
		return false;										// If Loading Failed, Return False

	//  The number of frames
	frameCount = 0;
	//  Number of frames per second
	fps = 0;
	//  currentTime - previousTime is the time elapsed
	//  between every call of the Idle function
	currentTime = 0, previousTime = 0;
	//  Pointer to a font style..
	//  Fonts supported by GLUT are: GLUT_BITMAP_8_BY_13, 
	//  GLUT_BITMAP_9_BY_15, GLUT_BITMAP_TIMES_ROMAN_10, 
	//  GLUT_BITMAP_TIMES_ROMAN_24, GLUT_BITMAP_HELVETICA_10,
	//  GLUT_BITMAP_HELVETICA_12, and GLUT_BITMAP_HELVETICA_18.
	//GLvoid *font_style = GLUT_BITMAP_TIMES_ROMAN_24;
	font_style = GLUT_BITMAP_TIMES_ROMAN_24;

	// realtime loop control
	timelastcall=timeGetTime();
	frequency = 30.0f;

	for(int i=0; i<255; i++){
		myKeys[i] = false;
	}
	angle = 0.0f;
	mouseInfo.lastX = 800 >> 1;
	mouseInfo.lastY = 600 >> 1;

	theProjectiles = new CProjectile[MAXPROJECTILES];
	m_iProjectileIndex = 0;

	// Initialise the sound engine
	theSoundEngine = createIrrKlangDevice();
	if (!theSoundEngine)
		return false;	// error starting up the sound engine

	previousVelocity = 0.0f;

	// For HealthBar
	m_iHeightOfBar = 30;
	m_iWidthOfBar = 150;

	// Scene Graph
	theRoot = new CGroup();
	CInstance* newInstance = new CInstance();
	newInstance->SetColor( 0.0, 0.0, 1.0 );
	theRoot->SetTransform( new CTransform(0, 0, 0) );
	theRoot->SetInstance( newInstance );

	Matrix4x4 tempMtx;

	newInstance = new CInstance();
	newInstance->SetColor( 0.0, 1.0, 1.0 );
//	tempMtx.Rotatef(45,0,0,1);
	tempMtx.Translatef(0,2,0);
	theRoot->AddChild(new CTransform(tempMtx), new CGroup(), newInstance);
	tempMtx.Clear();

	newInstance = new CInstance();
	newInstance->SetColor( 1.0, 1.0, 0.0 );
	tempMtx.Translatef(0,2,-2);
//	tempMtx.Rotatef(45,1,0,0);
//	tempMtx.Translatef(0,1,0);
	theRoot->AddChild(new CTransform(tempMtx), new CGroup(), newInstance);
	tempMtx.Clear();

	newInstance = new CInstance();
	newInstance->SetColor( 1.0, 0.0, 1.0 );
	tempMtx.Translatef(0,2,-4);
//	tempMtx.Scalef(1.1,1.1,1.1);
	theRoot->AddChild(new CTransform(tempMtx), new CGroup(), newInstance);
	tempMtx.Clear();

	theFrustum = new CFrustum;

	return true;
}


bool myApplication::LoadTGA(TextureImage *texture, char *filename)			// Loads A TGA File Into Memory
{    
	GLubyte		TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};	// Uncompressed TGA Header
	GLubyte		TGAcompare[12];								// Used To Compare TGA Header
	GLubyte		header[6];									// First 6 Useful Bytes From The Header
	GLuint		bytesPerPixel;								// Holds Number Of Bytes Per Pixel Used In The TGA File
	GLuint		imageSize;									// Used To Store The Image Size When Setting Aside Ram
	GLuint		temp;										// Temporary Variable
	GLuint		type=GL_RGBA;								// Set The Default GL Mode To RBGA (32 BPP)

	FILE *file = fopen(filename, "rb");						// Open The TGA File

	if(	file==NULL ||										// Does File Even Exist?
		fread(TGAcompare,1,sizeof(TGAcompare),file)!=sizeof(TGAcompare) ||	// Are There 12 Bytes To Read?
		memcmp(TGAheader,TGAcompare,sizeof(TGAheader))!=0				||	// Does The Header Match What We Want?
		fread(header,1,sizeof(header),file)!=sizeof(header))				// If So Read Next 6 Header Bytes
	{
		if (file == NULL)									// Did The File Even Exist? *Added Jim Strong*
			return false;									// Return False
		else
		{
			fclose(file);									// If Anything Failed, Close The File
			return false;									// Return False
		}
	}

	texture->width  = header[1] * 256 + header[0];			// Determine The TGA Width	(highbyte*256+lowbyte)
	texture->height = header[3] * 256 + header[2];			// Determine The TGA Height	(highbyte*256+lowbyte)
    
 	if(	texture->width	<=0	||								// Is The Width Less Than Or Equal To Zero
		texture->height	<=0	||								// Is The Height Less Than Or Equal To Zero
		(header[4]!=24 && header[4]!=32))					// Is The TGA 24 or 32 Bit?
	{
		fclose(file);										// If Anything Failed, Close The File
		return false;										// Return False
	}

	texture->bpp	= header[4];							// Grab The TGA's Bits Per Pixel (24 or 32)
	bytesPerPixel	= texture->bpp/8;						// Divide By 8 To Get The Bytes Per Pixel
	imageSize		= texture->width*texture->height*bytesPerPixel;	// Calculate The Memory Required For The TGA Data

	texture->imageData=(GLubyte *)malloc(imageSize);		// Reserve Memory To Hold The TGA Data

	if(	texture->imageData==NULL ||							// Does The Storage Memory Exist?
		fread(texture->imageData, 1, imageSize, file)!=imageSize)	// Does The Image Size Match The Memory Reserved?
	{
		if(texture->imageData!=NULL)						// Was Image Data Loaded
			free(texture->imageData);						// If So, Release The Image Data

		fclose(file);										// Close The File
		return false;										// Return False
	}

	for(GLuint i=0; i<int(imageSize); i+=bytesPerPixel)		// Loop Through The Image Data
	{														// Swaps The 1st And 3rd Bytes ('R'ed and 'B'lue)
		temp=texture->imageData[i];							// Temporarily Store The Value At Image Data 'i'
		texture->imageData[i] = texture->imageData[i + 2];	// Set The 1st Byte To The Value Of The 3rd Byte
		texture->imageData[i + 2] = temp;					// Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
	}

	fclose (file);											// Close The File

	// Build A Texture From The Data
	glGenTextures(1, &texture[0].texID);					// Generate OpenGL texture IDs

	glBindTexture(GL_TEXTURE_2D, texture[0].texID);			// Bind Our Texture
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);	// Linear Filtered
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);	// Linear Filtered
	
	if (texture[0].bpp==24)									// Was The TGA 24 Bits
	{
		type=GL_RGB;										// If So Set The 'type' To GL_RGB
	}

	glTexImage2D(GL_TEXTURE_2D, 0, type, texture[0].width, texture[0].height, 0, type, GL_UNSIGNED_BYTE, texture[0].imageData);

	return true;											// Texture Building Went Ok, Return True
}


void myApplication::renderGround(void) {
	glPushMatrix();
	glTranslatef( -10.0f, 0.0f, 0.0f );
	glColor3f(1.0,1.0,1.0);
	for (int x=0; x<4; x++)
	{
		for (int z=0; z<4; z++)
		{
			glBindTexture(GL_TEXTURE_2D, grassTexture[(x*4+z) % 5].texID);

			glBegin(GL_QUADS);
			glTexCoord2f(0.25f+x/4.0f, 0.25f+z/4.0f);	glVertex3f(0.0f+5.0f*x, 0.0f, 0.0f+5.0f*z);
			glTexCoord2f(x/4.0f, 0.25f+z/4.0f);			glVertex3f(5.0f+5.0f*x, 0.0f, 0.0f+5.0f*z);
			glTexCoord2f(x/4.0f, z/4.0f);					glVertex3f(5.0f+5.0f*x, 0.0f, 5.0f+5.0f*z);
			glTexCoord2f(0.25f+x/4.0f, z/4.0f);			glVertex3f(0.0f+5.0f*x, 0.0f, 5.0f+5.0f*z);
			glEnd();
		}
	}
	glPopMatrix();
}

void myApplication::renderSky(void) {
	float size = 100.0f;
	float overlap = size/1000;

	//glPushMatrix();
	//glColor3f(1.0,1.0,1.0);
	//	glBindTexture(GL_TEXTURE_2D, skyTexture[0].texID);

	//		glBegin(GL_QUADS);
	//		glTexCoord2f(1,0);			glVertex3f(-10,4,-10);
	//		glTexCoord2f(1,1);			glVertex3f(10,4,-10);
	//		glTexCoord2f(0,1);			glVertex3f(10,4,10);
	//		glTexCoord2f(0,0);			glVertex3f(-10,4,10);
	//		glEnd();
	//glPopMatrix();


	// Enable/Disable features
	glPushAttrib(GL_ENABLE_BIT);
	glEnable(GL_TEXTURE_2D);
//	glDisable(GL_DEPTH_TEST);
	glDisable(GL_LIGHTING);
	glDisable(GL_BLEND);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

	// Just in case we set all vertices to white.
	glColor4f(1,1,1,1);

	// Render the front quad
	glBindTexture(GL_TEXTURE_2D, skyTexture[0].texID);
	glBegin(GL_QUADS);
	glTexCoord2f(0, 0); glVertex3f(  size, -size, -size+overlap );
	glTexCoord2f(1, 0); glVertex3f( -size, -size, -size+overlap );
	glTexCoord2f(1, 1); glVertex3f( -size,  size, -size+overlap );
	glTexCoord2f(0, 1); glVertex3f(  size,  size, -size+overlap );
	glEnd();

	// Render the back quad
	glBindTexture(GL_TEXTURE_2D, skyTexture[1].texID);
	glBegin(GL_QUADS);
	glTexCoord2f(0, 0); glVertex3f( -size, -size,  size-overlap );
	glTexCoord2f(1, 0); glVertex3f(  size, -size,  size-overlap );
	glTexCoord2f(1, 1); glVertex3f(  size,  size,  size-overlap );
	glTexCoord2f(0, 1); glVertex3f( -size,  size,  size-overlap );

	glEnd();

	// Render the left quad
	glBindTexture(GL_TEXTURE_2D, skyTexture[2].texID);
	glBegin(GL_QUADS);
	glTexCoord2f(0, 0); glVertex3f(  size-overlap, -size,  size );
	glTexCoord2f(1, 0); glVertex3f(  size-overlap, -size, -size );
	glTexCoord2f(1, 1); glVertex3f(  size-overlap,  size, -size );
	glTexCoord2f(0, 1); glVertex3f(  size-overlap,  size,  size );
	glEnd();

	// Render the right quad
	glBindTexture(GL_TEXTURE_2D, skyTexture[3].texID);
	glBegin(GL_QUADS);
	glTexCoord2f(0, 0); glVertex3f( -size+overlap, -size, -size );
	glTexCoord2f(1, 0); glVertex3f( -size+overlap, -size,  size );
	glTexCoord2f(1, 1); glVertex3f( -size+overlap,  size,  size );
	glTexCoord2f(0, 1); glVertex3f( -size+overlap,  size, -size );
	glEnd();

	// Render the top quad
	glBindTexture(GL_TEXTURE_2D, skyTexture[4].texID);
	glBegin(GL_QUADS);
	glTexCoord2f(0, 1); glVertex3f( -size,  size-overlap, -size );
	glTexCoord2f(0, 0); glVertex3f( -size,  size-overlap,  size );
	glTexCoord2f(1, 0); glVertex3f(  size,  size-overlap,  size );
	glTexCoord2f(1, 1); glVertex3f(  size,  size-overlap, -size );
	glEnd();

	// Render the bottom quad
	glBindTexture(GL_TEXTURE_2D, skyTexture[5].texID);
	glBegin(GL_QUADS);
	glTexCoord2f(0, 0); glVertex3f( -size, -size+overlap, -size );
	glTexCoord2f(0, 1); glVertex3f( -size, -size+overlap,  size );
	glTexCoord2f(1, 1); glVertex3f(  size, -size+overlap,  size );
	glTexCoord2f(1, 0); glVertex3f(  size, -size+overlap, -size );
	glEnd();

	glDisable(GL_TEXTURE_2D);
//	glEnable(GL_DEPTH_TEST);
	glEnable(GL_LIGHTING);
	glEnable(GL_BLEND);

	// Restore enable bits and matrix
	glPopAttrib();
	glPopMatrix();

}

//-------------------------------------------------------------------------
// Calculates the frames per second
//-------------------------------------------------------------------------
void myApplication::calculateFPS()
{
    //  Increase frame count
    frameCount++;

    //  Get the number of milliseconds since glutInit called
    //  (or first call to glutGet(GLUT ELAPSED TIME)).
    currentTime = glutGet(GLUT_ELAPSED_TIME);

    //  Calculate time passed
    int timeInterval = currentTime - previousTime;

    if(timeInterval > 1000)
    {
        //  calculate the number of frames per second
        fps = frameCount / (timeInterval / 1000.0f);

        //  Set time
        previousTime = currentTime;

        //  Reset frame count
        frameCount = 0;
    }
}

//-------------------------------------------------------------------------
//  Draw FPS
//-------------------------------------------------------------------------
void myApplication::drawFPS()
{
    //  Load the identity matrix so that FPS string being drawn
    //  won't get animates
	glLoadIdentity ();

	//  Print the FPS to the window
	if (fps > 28.30f)
		glColor3f( 1.0f, 1.0f, 0.0f);
	else if (fps > 28.0f)
		glColor3f( 1.0f, 0.0f, 1.0f);
	else 
		glColor3f( 1.0f, 0.0f, 0.0f);
	printw (25.0, 25.0, 0, "FPS: %4.2f", fps);
}

//-------------------------------------------------------------------------
//  Draws a string at the specified coordinates.
//-------------------------------------------------------------------------
void myApplication::printw (float x, float y, float z, char* format, ...)
{
	va_list args;	//  Variable argument list
	int len;		//	String length
	int i;			//  Iterator
	char * text;	//	Text

	//  Initialize a variable argument list
	va_start(args, format);

	//  Return the number of characters in the string referenced the list of arguments.
	//  _vscprintf doesn't count terminating '\0' (that's why +1)
	len = _vscprintf(format, args) + 1; 

	//  Allocate memory for a string of the specified size
	text = (char *)malloc(len * sizeof(char));

	//  Write formatted output using a pointer to the list of arguments
	vsprintf_s(text, len, format, args);

	//  End using variable argument list 
	va_end(args);

	//  Specify the raster position for pixel operations.
	glRasterPos3f (x, y, z);


	//  Draw the characters one by one
    for (i = 0; text[i] != '\0'; i++)
        glutBitmapCharacter(font_style, text[i]);

	//  Free the allocated memory for the string
	free(text);
}

// Draw the healthbar in the OpenGL window
void myApplication::DrawHealthBar(const int m_iHealth, const int m_iMaxHealth)
{
	glBegin(GL_QUADS);
		glTexCoord2f(0,0); glVertex2f(600,500);
		glTexCoord2f(1,0); glVertex2f(600,500 + m_iHeightOfBar);
		glTexCoord2f(1,1); glVertex2f(600+((float)m_iHealth/m_iMaxHealth)*m_iWidthOfBar,500 + m_iHeightOfBar);
		glTexCoord2f(0,1); glVertex2f(600+((float)m_iHealth/m_iMaxHealth)*m_iWidthOfBar,500);	
	glEnd();
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	glBegin(GL_QUADS);
		glTexCoord2f(0,0); glVertex2f(600,500);
		glTexCoord2f(1,0); glVertex2f(600,500 + m_iHeightOfBar);
		glTexCoord2f(1,1); glVertex2f(600+m_iWidthOfBar,500 + m_iHeightOfBar);
		glTexCoord2f(0,1); glVertex2f(600+m_iWidthOfBar,500);	
	glEnd();
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
